package com.server.controller;

import com.comm.constance.CommonInstance;
import com.comm.entity.po.LoginUserInfo;
import com.comm.result.ResponseResult;
import com.comm.utils.VerifyCodeUtils;
import com.server.feignApi.BusinessUserApi;
import com.server.message.RabbitMqMsgHandle;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import kotlin.Deprecated;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @Description: TODO
 * @Author: mis_wu
 * @Date: 2022/7/20
 **/
@RestController
@RequestMapping("/userServeController")
@Slf4j
@Api(tags = "用户登录相关操作",value = "用户操作")
public class UserController {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private BusinessUserApi userApi;

    @PostMapping("/userLoginVerify")
    @ApiOperation("用户登录操作")
    ResponseResult<LoginUserInfo> userLoginVerify(@RequestBody LoginUserInfo loginUserInfo){
        log.info("用户登录操作,userLoginVerify,参数:{}",loginUserInfo);
        return userApi.userLoginVerify(loginUserInfo);
    }

    @GetMapping("/getSmsCodeByPhone")
    @ApiOperation("发送短信验证码")
    ResponseResult<Boolean> sendSmsCodeByPhone(@RequestParam String phone){
        log.info("发送验证码,手机号:{}",phone);
        return userApi.sendSmsCodeByPhone(phone);
    }

    @GetMapping("/getEmailCodeByEmail")
    @ApiOperation("发送邮箱验证码")
    ResponseResult<Boolean> getEmailCodeByEmail(@RequestParam String email){
        log.info("发送验证码,邮箱:{}",email);
        return userApi.sendEmailCodeByEmail(email);
    }

    @PostMapping("/preLoginCheck")
    @ApiOperation("预登录检查-禁止重复提交")
    @Deprecated(message = "废弃,幂等性校验在网关实现")
    ResponseResult<Boolean> preLoginCheck(HttpServletRequest request){
        String idempotenceKey = request.getHeader("idempotenceKey");
        if (StringUtils.isEmpty(idempotenceKey)){
            return ResponseResult.error(false);
        }
        boolean result = LoginIdempotenceJudge(idempotenceKey, this.getClass());
        return ResponseResult.isSuccess(result);
    }


    /**
     * 登录幂等性判断
     * @param key id
     * @param lockClass lockClass
     * @return boolean
     * 第一次请求进来  redis肯定是空的,接着保存key,true
     * 第二次请求进来  如果在过期时间之内的 redis肯定不为空,false
     * ...n次请求进来 如果过期时间到了,redis为空,重新请求即可
     */
    public boolean LoginIdempotenceJudge(String key, Object lockClass) {
        synchronized (lockClass) {
            // 重复请求判断
            String keyStr = stringRedisTemplate.opsForValue().get(key);
            if (StringUtils.isNotEmpty(keyStr)){
                log.info("请求重复提交了,或点击过快...");
                return false;
            }
            // keyStr为空,说明到期了 非重复请求,存储请求 key,并设置过期时间
            log.info("request repeat commit key:{}",key);
            Boolean absent = stringRedisTemplate.opsForValue().setIfAbsent(key, key + "_" + System.currentTimeMillis(), 2, TimeUnit.SECONDS);
            if (Boolean.FALSE.equals(absent)){
                log.info("redis设置请求重复提交key失败,请检查,key:{}",key);
                return false;
            }
        }
        return true;
    }

    @PostMapping("/logout")
    @ApiOperation("退出登录")
    public ResponseResult<Boolean> logout(){
        List<String> keysList = Arrays.asList(CommonInstance.REDIS_IMG_KEY, CommonInstance.LOGIN_USER_KEY);
        Long delete = stringRedisTemplate.delete(keysList);
        return ResponseResult.isSuccess(null != delete && 0L != delete);
    }

    @ApiOperation("生成验证码")
    @GetMapping("/getImageCode")
    public void getImage(HttpServletResponse response) throws IOException {
        //每次进来先清除调已存在的key,不管过期与否,保证只存在一个
        stringRedisTemplate.delete(CommonInstance.REDIS_IMG_KEY);
        //生成验证码
        String securityCode = VerifyCodeUtils.getSecurityCode();
        //将验证码放入session
        stringRedisTemplate.opsForValue().set(CommonInstance.REDIS_IMG_KEY,securityCode,1,TimeUnit.MINUTES);
        //生成图片
        BufferedImage image = VerifyCodeUtils.createImage(securityCode);
        //输出图片
        ServletOutputStream outputStream = response.getOutputStream();
        //调用工具类
        ImageIO.write(image,"png",outputStream);
        log.info("获取验证码成功!!!");
    }

    @GetMapping("/getRabbitMsg")
    public ResponseResult<Object> getRabbitMsg(){
        ResponseResult<Object> receiveMessage = RabbitMqMsgHandle.getReceiveMessage();
        log.info("接收消息控制器");
        return ResponseResult.isSuccess(receiveMessage.getData());
    }


}
